package no.ntnu.fp.gui.mainFrame;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Calendar;
import java.util.Date;
import java.util.EventObject;
import java.util.HashMap;
import java.util.Map;

import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

import no.ntnu.fp.client.Client;
import no.ntnu.fp.client.exceptions.NetworkException;
import no.ntnu.fp.gui.EventDispatcher;
import no.ntnu.fp.gui.calendar.CalendarPanel;
import no.ntnu.fp.gui.calendar.SmallCalendar;
import no.ntnu.fp.gui.dialog.DialogFrame;
import no.ntnu.fp.gui.dialog.ParticipantDialog;
import no.ntnu.fp.gui.events.LogoutRequestedEvent;
import no.ntnu.fp.gui.login.Login;
import no.ntnu.fp.gui.notice.NoticeBoard;
import no.ntnu.fp.model.events.DialogEmployeesChangeEvent;
import no.ntnu.fp.model.events.EmployeeChangedEvent;
import no.ntnu.fp.model.events.LoggedInChangedEvent;
import no.ntnu.fp.model.events.ModelEvent;
import no.ntnu.fp.model.listeners.ModelListener;


/**
 * Sketch of implementation of {@link MainFrame} interface
 * @author benjamin
 *
 */
@SuppressWarnings("serial")
public class MainFrame extends JFrame implements ModelListenerProvider {

    private final Login login = new Login(this);
    private final DialogFrame appointmentDialog;
    private final MainFrameMenubar menubar;
    private boolean closeWindow;
    private final SmallCalendar calWidget;
    private final CalendarPanel calPanel;
    private final NoticeBoard noticeBoard;
    private final Calendar calendar;

    public MainFrame(Calendar calendar) {
   	 this.calendar = calendar;
   	 setTitle("Calendar");
   	 // viser ikon i venstre hj�rne
   	 setIconImage(new ImageIcon("images/calendarIcon.png").getImage());
   	 this.setExtendedState(this.getExtendedState()|JFrame.MAXIMIZED_BOTH);
   	 setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
   	 menubar = new MainFrameMenubar(new QuitAction());
   	 closeWindow = false;
   	 setJMenuBar(menubar);
   	 JPanel content = new JPanel();
   	 GridBagLayout gbl = new GridBagLayout();
   	 content.setLayout(gbl);
   	 
   	 //Toolbar gbc
   	 GridBagConstraints tbC = new GridBagConstraints();
   	 tbC.gridx = 0;
   	 tbC.gridy = 1;
   	 tbC.fill = GridBagConstraints.VERTICAL;
   	 tbC.anchor = GridBagConstraints.SOUTH;
   	 tbC.gridheight = 5;
   	 tbC.insets = new Insets(70,5,0,5);
   	 
   	 //Calendar gbc
   	 GridBagConstraints calC = new GridBagConstraints();
   	 calC.gridx = 1;
   	 calC.gridy = 0;
   	 calC.fill = GridBagConstraints.VERTICAL;
   	 calC.fill = GridBagConstraints.HORIZONTAL;
   	 calC.weightx = 0.67;
   	 calC.ipady = 450;
   	 calC.gridheight = 6;
   	 calC.gridwidth = 3;
   	 
   	 //InfoField gbc
   	 GridBagConstraints infoC = new GridBagConstraints();
   	 infoC.gridx = 1;
   	 infoC.gridy = 6;
   	 infoC.fill = GridBagConstraints.VERTICAL;
   	 infoC.gridwidth = 3;
   	 infoC.insets = new Insets(10,2,2,2);
   	 
   	 //Hva som helst og commiter det
   	 
   	 //Calendar widget gbc
   	 GridBagConstraints widgC = new GridBagConstraints();
   	 widgC.gridx = 4;
   	 widgC.gridy = 0;
   	 widgC.fill = GridBagConstraints.VERTICAL;
   	 widgC.ipady = 100;
   	 widgC.weightx = 0.15;
   	 widgC.gridheight = 3;
   	 
   	 //Notice gbc
   	 GridBagConstraints ntcC = new GridBagConstraints();
   	 ntcC.gridx = 4;
   	 ntcC.gridy = 3;
   	 ntcC.ipadx = 250;
   	 ntcC.weightx = 0.5;
   	 ntcC.fill = GridBagConstraints.VERTICAL;
   	 ntcC.anchor = GridBagConstraints.SOUTH;
   	 ntcC.gridheight = 4;
   	 
   	 calPanel = CalendarPanel.getInstance();
   	 calPanel.setSelectWeekListeners(new NextWeekAction(), new PreviousWeekAction());
   	 InfoField information = new InfoField();
   	 calPanel.addPropertyChangeListener(information);

   	 calWidget = new SmallCalendar(calendar);
   	 calWidget.setTableListener(new CalendarWidgetWeekChangeListener());
   	 calWidget.setSelectMonthListeners(new NextMonthAction(), new PreviousMonthAction());
   	 noticeBoard = new NoticeBoard();
   	 JPanel noticePanel = new JPanel();
   	 noticePanel.add(noticeBoard);
   	 BoxLayout bl = new BoxLayout(noticePanel, BoxLayout.Y_AXIS);
   	 noticePanel.setLayout(bl);
   	 content.add(Toolbar.getInstance(), tbC);
   	 content.add(calPanel, calC);
   	 content.add(information, infoC);
   	 content.add(calWidget, widgC);
   	 content.add(noticePanel, ntcC);
   	 this.add(content);
   	 login.addWindowListener(new WindowAdapter() {
   		 @Override
   		 public void windowClosing(WindowEvent e) {
   			 processWindowEvent(e);
   		 }
   	 });
   	 this.addWindowListener(new WindowAdapter() {
   		 @Override
   		 public void windowClosing(WindowEvent e){
   			 if(e.getSource() == login){
   				 MainFrame.this.closeApplication();
   			 }
   			 MainFrame.this.requestFocus();
   			 int answer = JOptionPane.showConfirmDialog(MainFrame.this,
   					 "Er du sikker på at du vil logge ut og avslutte programmet?",
   					 "Avslutte?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
   			 if(answer == JOptionPane.YES_OPTION){
   				 closeWindow = true;
   				 try {
   					 LogoutRequestedEvent evt = new LogoutRequestedEvent(this, Client.getEmployee());
   					 EventDispatcher.dispatchEvent(evt);
   				 } catch (NetworkException ex) {
   					 ex.printStackTrace();
   					 MainFrame.this.closeApplication();
   				 }
   			 }

   		 }
   	 });
   	 
   	 appointmentDialog = new DialogFrame(this, calendar);
    }
    private final class NextWeekAction implements ActionListener{

   	 @Override
   	 public void actionPerformed(ActionEvent e) {
   		 int currentWeek = calendar.get(Calendar.WEEK_OF_YEAR);
   		 calendar.set(Calendar.WEEK_OF_YEAR, currentWeek + 1);
   		 calPanel.updateDate();
   		 calWidget.updateDate();
   		 
//   		 MainFrame.this.calPanel.setWeekAndYear(
//   				 MainFrame.this.calPanel.getWeek() + 1, calPanel.getYear());
//   		 calWidget.setWeekAndYear(MainFrame.this.calPanel.getWeek(),
//   								 calPanel.getYear());
   	 }
    }
    private final class PreviousWeekAction implements ActionListener{

   	 @Override
   	 public void actionPerformed(ActionEvent e) {
   		 int currentWeek = calendar.get(Calendar.WEEK_OF_YEAR);
   		 calendar.set(Calendar.WEEK_OF_YEAR, currentWeek - 1);
   		 //int currentWeek2 = calendar.get(Calendar.WEEK_OF_YEAR);
   		 calPanel.updateDate();
   		 calWidget.updateDate();
//   		 MainFrame.this.calPanel.setWeekAndYear(
//   				 MainFrame.this.calPanel.getWeek() - 1, calPanel.getYear());
//   		 calWidget.setWeekAndYear(MainFrame.this.calPanel.getWeek(),
//   								 calPanel.getYear());
   	 }
    }
    
    private final class PreviousMonthAction implements ActionListener {
   	 @Override
   	 public void actionPerformed(ActionEvent e) {
   		 int currentMonth = calendar.get(Calendar.MONTH);
   		 calendar.set(Calendar.MONTH, currentMonth - 1);
   		 calPanel.updateDate();
   		 calWidget.updateDate();
   	 }
    }
    
    private final class NextMonthAction implements ActionListener {
   	 @Override
   	 public void actionPerformed(ActionEvent e) {
   		 int currentMonth = calendar.get(Calendar.MONTH);
   		 calendar.set(Calendar.MONTH, currentMonth + 1);
   		 calPanel.updateDate();
   		 calWidget.updateDate();
   	 }
    }

    public final static class CalendarWidgetWeekChangeEvent extends EventObject {
   	 private final int weekOfMonth;
   	 
   	 public CalendarWidgetWeekChangeEvent(Object source, int weekOfMonth) {
   		 super(source);
   		 this.weekOfMonth = weekOfMonth;
   	 }
   	 
   	 public int getWeekOfMonth() {
   		 return weekOfMonth;
   	 }
    }
    
    public final class CalendarWidgetWeekChangeListener {
   	 
   	 public void weekChanged(CalendarWidgetWeekChangeEvent e) {
   		 int weekOfMonth = e.getWeekOfMonth();
   		 calendar.set(Calendar.WEEK_OF_MONTH, weekOfMonth);
   		 calPanel.updateDate();
   		 calWidget.updateDate();
   		 
//   		 if (registeredWeekInMonth != weekOfMonth) {
//   		 }
   		 
//   		 int[] weekAndYear = calWidget.getWeekAndYear();
//   		 if(calPanel.getWeek() != weekAndYear[0] ||
//   				 calPanel.getYear() != weekAndYear[1]) {
//   			 calPanel.setWeekAndYear(weekAndYear[0], weekAndYear[1]);
//   		 }
   	 }
    }


    @Override
    public void setVisible(boolean b) {
   	 super.setVisible(b);
   	 login.setVisible(b);
    }

    private void closeApplication(){
   	 MainFrame.this.setVisible(false);
   	 System.exit(0);
    }

    private final class QuitAction implements ActionListener{
   	 @Override
   	 public void actionPerformed(ActionEvent arg0) {
   		 processWindowEvent(new WindowEvent(MainFrame.this, WindowEvent.WINDOW_CLOSING));
   	 }
    }

    private final class LoginChangedListener implements ModelListener<LoggedInChangedEvent> {
   	 @Override
   	 public void handleEvent(LoggedInChangedEvent event) {
   		 if (!event.wasLoggedIn()) {   			 
   			 if(event.isLoggedIn()){
   				 login.setVisible(false);
   			 }else{
   				 login.loginFailed(event.getError());
   			 }
   		 } else if(event.wasLoggedIn() && !event.isLoggedIn()){
   			 if(closeWindow){
   				 MainFrame.this.closeApplication();
   			 }
//   			 calPanel.setWeekAndYear(calPanel.getWeek(), calPanel.getYear());
   			 calendar.setTime(new Date());
   			 calPanel.updateDate();
   			 calWidget.updateDate();
   			 setTitle("Calendar");
   			 login.showLoginProgressbar(false);
   			 login.setVisible(true);

   		 }else {
   			 throw new UnsupportedOperationException("Not yet implemented");
   		 }
   	 }
    }

    private final class EmployeeChangedListener implements ModelListener<EmployeeChangedEvent> {
   	 @Override
   	 public void handleEvent(EmployeeChangedEvent event) {
   		 calPanel.setEmployee(event.getNewEmployee());
   		 setTitle(getTitle() + ", Logged in as " + event.getNewEmployee());
   		 Client.setEmployee(event.getNewEmployee());
   	 }
    }

    @Override
    public Map<Class<? extends ModelEvent>, ModelListener<?>> getEventListeners() {
   	 Map<Class<? extends ModelEvent>, ModelListener<?>> map =
   		 new HashMap<Class<? extends ModelEvent>, ModelListener<?>>();

   	 map.put(LoggedInChangedEvent.class, new LoginChangedListener());
   	 map.put(EmployeeChangedEvent.class, new EmployeeChangedListener());
   	 map.put(DialogEmployeesChangeEvent.class, ParticipantDialog.getInstance());
   	 map.putAll(calPanel.getEventListeners());
   	 map.putAll(noticeBoard.getEventListeners());
   	 map.putAll(appointmentDialog.getEventListeners());
   	 return map;
    }

}
